﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using HigLabo.Net.Extensions;
using Newtonsoft.Json;
using System.Net;

namespace HigLabo.Net.Facebook
{
    /// <summary>
    /// 
    /// </summary>
    public partial class FacebookClient
    {
        private String GetBodyText(FacebookCommand command)
        {
            return this.GetBodyText(HttpMethodName.Get, command);
        }
        private String GetBodyText(HttpMethodName methodName, FacebookCommand command)
        {
            var cm = this.CreateCommand(methodName, command);
            try
            {
                return this.GetBodyText(cm);
            }
            catch (WebException ex)
            {
                var res = ex.Response as HttpWebResponse;
                if (res == null) { throw; }
                throw new FacebookResponseException(ex);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public FqlResult Fql(String query)
        {
            return Fql(query, HttpClient.UrlEncode);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <param name="urlEncodingFunction"></param>
        /// <returns></returns>
        public FqlResult Fql(String query, Func<String, String> urlEncodingFunction)
        {
            String url = String.Format("https://graph.facebook.com/fql?q={0}&access_token={1}", urlEncodingFunction(query), this.AccessToken);
            var cm = new HttpRequestCommand(url);
            String text = this.GetBodyText(cm);
            return new FqlResult(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public User GetUser()
        {
            return this.GetUser("me");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public User GetUser(String id)
        {
            return this.GetUser(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public User GetUser(GetObjectCommand command)
        {
            var cm = command;
            String text = this.GetBodyText(cm);
            return new User(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Page GetPage(String id)
        {
            return this.GetPage(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Page GetPage(GetObjectCommand command)
        {
            var cm = command;
            String text = this.GetBodyText(cm);
            return new Page(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public PostData GetHome()
        {
            var cm = new GetObjectConnectionCommand("me", FacebookConnetionType.Home);
            String text = this.GetBodyText(cm);
            return new PostData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public PostData GetHome(String id)
        {
            return this.GetHome(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public PostData GetHome(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Home);
            String text = this.GetBodyText(cm);
            return new PostData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public PostData GetFeed()
        {
            var cm = new GetObjectConnectionCommand("me", FacebookConnetionType.Feed);
            String text = this.GetBodyText(cm);
            return new PostData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public PostData GetFeed(String id)
        {
            return this.GetFeed(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public PostData GetFeed(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Feed);
            String text = this.GetBodyText(cm);
            return new PostData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public PostData GetStatuses()
        {
            var cm = new GetObjectConnectionCommand("me", FacebookConnetionType.Statuses);
            String text = this.GetBodyText(cm);
            return new PostData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public PostData GetStatuses(String id)
        {
            return this.GetStatuses(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public PostData GetStatuses(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Statuses);
            String text = this.GetBodyText(cm);
            return new PostData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public PostData GetPosts(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Statuses);
            String text = this.GetBodyText(cm);
            return new PostData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public PostData GetPostData(PostData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new PostData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public LikeData GetLikes(String id)
        {
            return this.GetLikes(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public LikeData GetLikes(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Likes);
            String text = this.GetBodyText(cm);
            return new LikeData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public LikeData GetLikes(LikeData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new LikeData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Comment GetComment(String id)
        {
            return this.GetComment(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Comment GetComment(GetObjectCommand command)
        {
            var cm = command;
            String text = this.GetBodyText(cm);
            return new Comment(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public CommentData GetComments(String id)
        {
            return this.GetComments(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public CommentData GetComments(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Comments);
            String text = this.GetBodyText(cm);
            return new CommentData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public CommentData GetComments(CommentData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new CommentData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Album GetAlbum(String id)
        {
            return this.GetAlbum(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Album GetAlbum(GetObjectCommand command)
        {
            var cm = command;
            String text = this.GetBodyText(cm);
            return new Album(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public AlbumData GetAlbums(String id)
        {
            return this.GetAlbums(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public AlbumData GetAlbums(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Albums);
            String text = this.GetBodyText(cm);
            return new AlbumData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public AlbumData GetAlbums(AlbumData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new AlbumData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Book GetBook(String id)
        {
            return this.GetBook(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Book GetBook(GetObjectCommand command)
        {
            var cm = command;
            String text = this.GetBodyText(cm);
            return new Book(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public BookData GetBooks(String id)
        {
            return this.GetBooks(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public BookData GetBooks(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Books);
            String text = this.GetBodyText(cm);
            return new BookData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public BookData GetBooks(BookData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new BookData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Music GetMusic(String id)
        {
            return this.GetMusic(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Music GetMusic(GetObjectCommand command)
        {
            var cm = command;
            String text = this.GetBodyText(cm);
            return new Music(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public MusicData GetMusicList(String id)
        {
            return this.GetMusicList(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public MusicData GetMusicList(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Music);
            String text = this.GetBodyText(cm);
            return new MusicData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public MusicData GetMusicList(MusicData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new MusicData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Movie GetMovie(String id)
        {
            return this.GetMovie(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Movie GetMovie(GetObjectCommand command)
        {
            var cm = command;
            String text = this.GetBodyText(cm);
            return new Movie(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public MovieData GetMovies(String id)
        {
            return this.GetMovies(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public MovieData GetMovies(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Movies);
            String text = this.GetBodyText(cm);
            return new MovieData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public MovieData GetMovies(MovieData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new MovieData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Television GetTelevision(String id)
        {
            return this.GetTelevision(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public Television GetTelevision(GetObjectCommand command)
        {
            var cm = command;
            String text = this.GetBodyText(cm);
            return new Television(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public TelevisionData GetTelevisions(String id)
        {
            return this.GetTelevisions(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public TelevisionData GetTelevisions(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Television);
            String text = this.GetBodyText(cm);
            return new TelevisionData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public TelevisionData GetTelevisions(TelevisionData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new TelevisionData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public User GetFriend(String id)
        {
            return this.GetFriend(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public User GetFriend(GetObjectCommand command)
        {
            var cm = command;
            String text = this.GetBodyText(cm);
            return new User(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public FriendData GetFriends(String id)
        {
            return this.GetFriends(new GetObjectCommand(id));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public FriendData GetFriends(GetObjectCommand command)
        {
            var cm = new GetObjectConnectionCommand(command, FacebookConnetionType.Friends);
            String text = this.GetBodyText(cm);
            return new FriendData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public FriendData GetFriends(FriendData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new FriendData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public NotificationData GetNotifications()
        {
            var cm = new GetObjectConnectionCommand("me", FacebookConnetionType.Notifications);
            String text = this.GetBodyText(cm);
            return new NotificationData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public NotificationData GetNotifications(NotificationData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new NotificationData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public InboxData GetInbox()
        {
            var cm = new GetObjectConnectionCommand("me", FacebookConnetionType.Inbox);
            String text = this.GetBodyText(cm);
            return new InboxData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public InboxData GetInbox(InboxData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new InboxData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public OutboxData GetOutbox()
        {
            var cm = new GetObjectConnectionCommand("me", FacebookConnetionType.Outbox);
            String text = this.GetBodyText(cm);
            return new OutboxData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        public OutboxData GetOutbox(OutboxData data, PagingMode mode)
        {
            var url = data.Paging.GetUrl(mode);
            if (String.IsNullOrEmpty(url) == true) { return null; }
            var cm = this.CreateCommand(HttpMethodName.Get, url);
            String text = this.GetBodyText(cm);
            return new OutboxData(text);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Boolean Like(String id)
        {
            var cm = new FacebookCommand(id + "/likes");
            var text = this.GetBodyText(HttpMethodName.Post, cm);
            return String.Equals(text, "true", StringComparison.OrdinalIgnoreCase);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Boolean UnLike(String id)
        {
            var cm = new FacebookCommand(id + "/likes");
            var text = this.GetBodyText(HttpMethodName.Delete, cm);
            return String.Equals(text, "true", StringComparison.OrdinalIgnoreCase);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String AddComment(AddCommentCommand command)
        {
            var jsonText = this.GetBodyText(HttpMethodName.Post, command);
            var d = JsonConvert.DeserializeObject<Dictionary<String, Object>>(jsonText);
            return d.ToString("id");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public String AddStatus(AddStatusCommand command)
        {
            var jsonText = this.GetBodyText(HttpMethodName.Post, command);
            var d = JsonConvert.DeserializeObject<Dictionary<String, Object>>(jsonText);
            return d.ToString("id");
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Boolean DeleteObject(String id)
        {
            var cm = new FacebookCommand(id);
            return this.GetBodyText(HttpMethodName.Delete, cm) == "true";
        }
    }
}
